/*
 * CS_REQ_FAIRY_SACRIFICE.cpp
 *
 *  Created on: 2013. 7. 23.
 *      Author: mega@gamevil.com
 */

#include "../../Command.h"
#include "../../User.h"
#include "../../NUtil/Utils.h"
#include "../../NLogic/Bag.h"
#include "../../NLogic/Item.h"
#include "../../NLogic/Equip.h"
#include "../../NResource/Static.h"

#include "../../GameLog.h"

namespace ProjectZ { namespace NCommand {

void SendFailFairySacrifice(User * pUser, int res)
{
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pAck << static_cast<int16_t>(res);
	*pAck << static_cast<uint8_t>(0);
	*pAck << static_cast<uint64_t>(0);
	pAck->MakePacket(CMD_SC_REQ_FAIRY_SACRIFICE);
	pUser->Send(pAck);
}

void Command::CS_REQ_FAIRY_SACRIFICE(User * pUser, ::Network::Packet * pPacket)
{
/*	CS_REQ_FAIRY_SACRIFICE 0x01506 // 페어리 희생
	{
		u8  BagType;				// 아이템 가방
		u64	Item_seq;				// 아이템 seq ( 등급 업 할 아이템 )
		u8	item_quality;
		u64	Fairy_Item_seq;			// 아이템 seq ( 페어리 아이템 )
		u8	Fairy_quality;
	}

	SC_REQ_FAIRY_SACRIFICE 0x01507 // 페어리 희생
	{
		s16	u16ack;
		u8  BagType;
		u64	Item_seq;				// 아이템 seq
	}*/

	PREPARE_PACKET;

	uint8_t bagType 		= 0;
	uint64_t itemSeq		= 0;
	uint8_t itemQuality		= 0;
	uint64_t fairySeq		= 0;
	uint8_t fairyQuality	= 0;

	*pPacket >> bagType >> itemSeq >> itemQuality >> fairySeq >> fairyQuality;

	NResource::BalanceData * pBalance = NResource::Static::InstancePtr()->GetBalance()->GetBalancePtr(pUser);
	if (NULL == pBalance)
	{
		SendFailFairySacrifice(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	NLogic::Equip * pEquip = pUser->GetEquip();
	if (NULL == pEquip)
	{
		DEBUGLOG("CS_REQ_FAIRY_SACRIFICE : pEquip is NULL!!");
		SendFailFairySacrifice(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	// 장착된 페어리는 희생 불가
	NLogic::Item * pEquipFairy = pEquip->GetItem(ITEM_EQUIP_POS_FAIRY);
	if (NULL != pEquipFairy)
	{
		if (pEquipFairy->GetItemSeq() == fairySeq)
		{
			DEBUGLOG("CS_REQ_FAIRY_SACRIFICE : Ooops!! Equip Fairy!");
			SendFailFairySacrifice(pUser, ACK_UNKNOWN_ERROR);
			return;
		}
	}

	NLogic::Bag * pBag = pUser->GetBag(static_cast<INVEN_BAG_TYPE>(bagType));
	if (NULL == pBag)
	{
		DEBUGLOG("CS_REQ_FAIRY_SACRIFICE : pBag is NULL!!");
		SendFailFairySacrifice(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	NLogic::Bag * pBagFairy = pUser->GetBag(BAG_TYPE_FAIRY);
	if (NULL == pBagFairy)
	{
		DEBUGLOG("CS_REQ_FAIRY_SACRIFICE : pBagFairy is NULL!!");
		SendFailFairySacrifice(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	NLogic::Item * pItem = pBag->GetItem(itemSeq);
	if (NULL == pItem)
	{
		DEBUGLOG("CS_REQ_FAIRY_SACRIFICE : pItem is NULL!!");
		SendFailFairySacrifice(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	if (false == NResource::Static::Instance().GetItemResource()->isEquip(pItem->GetData()))
	{
		DEBUGLOG("%s : INVALID ITEM SHEET TYPE=%d", __FUNCTION__, pItem->GetData().sub_type);
		SendFailFairySacrifice(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	NLogic::Item * pFairy = pBagFairy->GetItem(fairySeq);
	if (NULL == pFairy)
	{
		DEBUGLOG("CS_REQ_FAIRY_SACRIFICE : pFairy is NULL!!");
		SendFailFairySacrifice(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	// 희생은 MAX OPEN 등급 이하 아이템 만 가능
	if (pItem->GetData().quality >= MAX_OPEN_ITEM_QUALITY)
	{
		SendFailFairySacrifice(pUser, ACK_NOT_ALLOW_FAIRY_SACRIFICE);
		return;
	}

	// 희생은 2성 이상 페어리만 가능
	if (pFairy->GetData().quality < 1)
	{
		SendFailFairySacrifice(pUser, ACK_NOT_ALLOW_FAIRY_SACRIFICE);
		return;
	}

	// 7성 이상의 아이템은 같은 등급 이상의 페어리로만 희생 가능
	if (pItem->GetData().quality >= 6)
	{
		if (pItem->GetData().quality > pFairy->GetData().quality)
		{
			SendFailFairySacrifice(pUser, ACK_NOT_ALLOW_FAIRY_SACRIFICE);
			return;
		}
	}

	// 페어리 희생 성공 여부 결정
	// 등급차 : n
	// 성공률 = 100 / (2 ^ n)

	// 페어리 등급이 아이템 등급보다 큰 경우는 확률 100%
	int nGap = pItem->GetData().quality - pFairy->GetData().quality;
	if (nGap < 0) {
		nGap = 0;
	}

	int nValue = (nGap == 0) ? 1 : pow(2, nGap);
	int succRate = 100 / nValue;
	int randRate = rand() % 100;

	int16_t res = ACK_FAIRY_SACRIFICE_FAIL;

	// 페어리 희생 성공. 아이템의 능력치 상승
	if (randRate < succRate)
	{
		res = ACK_OK;

		// 아이템 등급 증가
		pItem->GetData().quality += 1;

		// 아이템 기본 능력치 증가
		int addPer = pBalance->GetValue(EM_FAIRY_SACRIFICE_EFFECT_VALUE_UP_RATE);
		int newValue = NUtil::AddPercentage(pItem->GetData().eff_value[0], addPer);

		if (newValue == pItem->GetData().eff_value[0])
		{
			pItem->GetData().eff_value[0] += 1;
		}
		else
		{
			pItem->GetData().eff_value[0] = newValue;
		}

		// F등급 -> D등급으로 증가하는 경우 부가 능력치 부여
		if (pItem->GetData().quality == ITEM_QUALITY_D)
		{
			NResource::Static::InstancePtr()->GetItemResource()->SetAdditionalEffect(pItem->GetData(), true);
		}
		// D등급 이상으로 증가하는 경우 부가 능력치 +10%
		else
		{
			for (int i = 1; i <= 2; i++)
			{
				// 효과 타입이 'A'등급 이상에만 붙는 효과인 경우 효과값 증가
				if (pItem->GetData().eff_type[i] >= ITEM_EFFECT_QUALITY_A_MAX)
				{
					pItem->GetData().eff_value[i] += 1;
					continue;
				}

				// 부가 능력치 증가
				if (pItem->GetData().eff_type[i] > ITEM_EFFECT_NONE)
				{
					int newValue = NUtil::AddPercentage(pItem->GetData().eff_value[i], addPer * 2);

					if (newValue == pItem->GetData().eff_value[i])
					{
						if (pItem->GetData().eff_type[i] == ITEM_EFFECT_CONSUME_SP)
						{
							pItem->GetData().eff_value[i] -= 1;
						}
						else
						{
							pItem->GetData().eff_value[i] += 1;
						}
					}
					else
					{
						pItem->GetData().eff_value[i] = newValue;
					}
				}
			}
		}

		// 강화석 슬롯수 결정
		int slot = NResource::Static::InstancePtr()->GetItemResource()->GetItemOpenSlotCount(pItem->GetData());

		if (slot > pItem->GetData().open_upgrade_stone_slot)
		{
			pItem->GetData().open_upgrade_stone_slot = slot;
		}

		// 아이템의 등급이 올라감에 따라 제련 단계 결정
		pItem->GetData().max_enhance_step = NResource::Static::InstancePtr()->GetItemResource()->GetItemMaxRefine(pBalance, pItem->GetData());

		// 아이템 정보 갱신
		pItem->UpdateDatabaseItemInfo();

		NGameLog::LogItemInfo(pUser, FAIRY_SACRIFICE_ITEM, 1, 0, pItem);
	}
	else
	{
		NGameLog::LogItemInfo(pUser, FAIRY_SACRIFICE_ITEM, 0, 0, pItem);
	}

	// 재료 페어리 삭제
	pBagFairy->PopItem(fairySeq);
	pFairy->DeleteDatabaseItemInfo(NLogic::Item::ItemStatus::EM_ITEM_STATUS_FAIRY_SACRIFICE);

	// 응답
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pAck << res;
	*pAck << bagType;
	*pAck << pItem->GetItemSeq();
	pAck->MakePacket(CMD_SC_REQ_FAIRY_SACRIFICE);
	pUser->Send(pAck);
}

} /* NCommand */ } /* ProjectZ */

